#include "stdafx.h"
#include "Thread/WaitableTimerThread.h"
#include "Utils/FastBlockQueue.h"
#include "Utils/Callbackable.h"

void WaitableTimerThread::Run()
{
	bool quit = false;
	while(!quit)
	{
		QueueItem item = {0};
		bool isAlert = m_queue.AlertablePop(quit,item);
		if (isAlert || quit) 
		{
			continue;
		}
		else
		{
			if (item.type == QueueItem::WAITABLE_TIMER)
			{
				WaitableTimerParameter const& parameter = *(WaitableTimerParameter*)item.data;
				UpdateTimer(parameter);
			}
		}
	}
}

class WaitableTimerThread::WaitableTimer
{
	static VOID CALLBACK TimerAPCProc(LPVOID lpArgToCompletionRoutine,DWORD /*dwTimerLowValue*/,DWORD /*dwTimerHighValue*/)
	{
		WaitableTimer* waitableTimer = (WaitableTimer*)lpArgToCompletionRoutine;
		waitableTimer->Callback();
		delete waitableTimer;
	}

public:
	WaitableTimer(Callbackable* callback)
		:m_hWaitableTimer(::CreateWaitableTimer(NULL,FALSE,NULL)),m_callback(callback)
	{
	}
	~WaitableTimer()
	{
		::CloseHandle(m_hWaitableTimer);
	}
	void Start(SYSTEMTIME const& st)
	{
		FILETIME ftLocal, ftUTC;
		LARGE_INTEGER liUTC;
		::SystemTimeToFileTime(&st,&ftLocal);
		::LocalFileTimeToFileTime(&ftLocal,&ftUTC);
		liUTC.LowPart = ftUTC.dwLowDateTime;
		liUTC.HighPart = ftUTC.dwHighDateTime;
		::SetWaitableTimer(m_hWaitableTimer,&liUTC,0,TimerAPCProc,this,FALSE);
	}
	void Callback()
	{
		m_callback->Callback();
	}
private:
	HANDLE m_hWaitableTimer;
	Callbackable* m_callback;
};

void WaitableTimerThread::UpdateTimer(WaitableTimerParameter const& parameter)
{
	WaitableTimerMap::iterator iter = m_businessWaitableTimerMap.find(parameter.business);
	if (iter == m_businessWaitableTimerMap.end())
	{
		WaitableTimer* waitableTimer = new WaitableTimer(parameter.callback);
		waitableTimer->Start(parameter.st);
		m_businessWaitableTimerMap[parameter.business] = waitableTimer;
	}
	else
	{
		iter->second->Start(parameter.st);
	}
}